package cc.rengu.igas.share.core.service.channel.upac;

import cc.rengu.igas.channel.upac.facade.base.Header;
import cc.rengu.igas.channel.upac.facade.bean.CustomerInfo;
import cc.rengu.igas.channel.upac.facade.request.RepayRequest;
import cc.rengu.igas.channel.upac.facade.response.RepayResponse;
import cc.rengu.igas.channel.upac.facade.result.Result;
import cc.rengu.igas.share.common.constant.ShareParamConstant;
import cc.rengu.igas.share.common.constant.ShareServiceConstant;
import cc.rengu.igas.share.common.constant.TransCacheConstant;
import cc.rengu.oltp.service.base.ChannelBaseService;
import cc.rengu.oltp.service.common.constant.AppParamConstant;
import cc.rengu.oltp.service.common.constant.TreeNodeConstant;
import cc.rengu.oltp.service.common.entity.ChannelCallCfg;
import cc.rengu.oltp.service.common.entity.PayOrderInfo;
import cc.rengu.oltp.service.common.entity.SysParam;
import cc.rengu.oltp.service.common.enums.*;
import cc.rengu.oltp.service.model.BizException;
import cc.rengu.oltp.service.model.BizResponse;
import cc.rengu.oltp.service.model.OrderInfo;
import cc.rengu.oltp.service.model.TxnInfo;
import cc.rengu.oltp.service.realize.DubboService;
import cc.rengu.oltp.service.realize.SysParamService;
import cc.rengu.oltp.service.realize.impl.DubboServiceImpl;
import cc.rengu.oltp.service.realize.impl.SysParamServiceImpl;
import cc.rengu.oltp.utility.util.*;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;

/**
 * UPAC 银联全渠道单笔代付
 * Created by lzl on 2021/4/23 11:08
 */
public class RepayService extends ChannelBaseService {

    /**
     * 默认渠道类型 07-互联网
     */
    private final static String DEFAULT_CHANNEL_TYPE = "07";
    /**
     * 通道类型为代付PT01 PT?? 商户选择其开通的产品时取自支付通道信息表T_P_DST_CHANNEL_CFG
     */
    private final static String DST_CHANNEL_TYPE = "PT01";
    /**
     * 默认资金来源 00-一般性付款
     */
    private final static String DEFAULT_SOURCE_OF_FUNDS = "00";

    @Override
    public Object callPreProc(TxnInfo txnInfo, ChannelCallCfg channelCallCfg, OrderInfo orderInfo) throws Exception {
        XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
        Header upacHeader = new Header();
        upacHeader.setInstId(xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.INST_ID));
        upacHeader.setChanlId(channelCallCfg.getMsgSrcId());
        upacHeader.setSrcSysId(AppParamConstant.SYS_ID);
        upacHeader.setBizType(AppParamConstant.DEFAULT_BIZ_TYPE);
        upacHeader.setVersion(ShareParamConstant.DUBBO_VSERSION);
        upacHeader.setTxnNum(channelCallCfg.getCallChannelTxn());
        upacHeader.setTraceNo(xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.SYS_SEQ_NUM) + channelCallCfg.getCallIndex());
        upacHeader.setTransTime(xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.TRANS_TIME));
        upacHeader.setTransDate(xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.TRANS_DATE));
        RepayRequest repayRequest = new RepayRequest();
        ConvertUtil.convertOutput(repayRequest);
        repayRequest.setHeader(upacHeader);

        repayRequest.setChannelType(DEFAULT_CHANNEL_TYPE);
        repayRequest.setProdType(DST_CHANNEL_TYPE);

        String esbSequenceNumber = null;
        String esbGlobalTraceNum = null;
        String esbGlobalPathNum = null;
        String mchntNo = null;
        String sysSeqNum = null;
        if (!StringUtil.isEmptyOrNull(xmlTreeUtil.getXmlTreeStringValue("AdditionInfo"))) {
            JSONObject jsonObject = JSONObject.parseObject(xmlTreeUtil.getXmlTreeStringValue("AdditionInfo"));
            if (null == jsonObject) {
                rglog.error("附加信息中存在esb流水相关信息必须存在");
                return null;
            }
            esbSequenceNumber = jsonObject.getString(ShareParamConstant.ESB_SEQUENCE_NUMBER);
            esbGlobalTraceNum = jsonObject.getString("globalTraceNum");
            esbGlobalPathNum = jsonObject.getString("globalPathNum");
            sysSeqNum = (String) jsonObject.get(TreeNodeConstant.SYS_SEQ_NUM);
            if (StringUtil.isEmptyOrNull(esbSequenceNumber) || StringUtil.isEmptyOrNull(esbGlobalTraceNum) ||
                    StringUtil.isEmptyOrNull(esbGlobalPathNum) || StringUtil.isEmptyOrNull(sysSeqNum)) {
                rglog.error("附加信息中存在esb流水相关信息必须存在");
                return null;
            }
            mchntNo = jsonObject.getString("upacMchntNo");
            if (!StringUtil.isEmptyOrNull(mchntNo)) {
                repayRequest.setUpacMchntNo(mchntNo);
                SysParamService sysParamService = new SysParamServiceImpl();
                SysParam sysParam = sysParamService.getSysParamInfo(xmlTreeUtil.getXmlTreeStringValue("Header().getInstId"), "ROUTE:UPAC:MCHNT2PROD:PT", mchntNo);
                if (null != sysParam && !StringUtil.isEmptyOrNull(sysParam.getParamValue())) {
                    repayRequest.setProdType(sysParam.getParamValue());
                } else {
                    rglog.error("该商户<{}>未配置其产品映射关系", mchntNo);
                    return null;
                }
            }
        }

        //账户类型
        repayRequest.setAcctType(xmlTreeUtil.getXmlTreeStringValue("PayeeInfo().getAcctType"));
        //银行账号
        repayRequest.setPayAcctNo(xmlTreeUtil.getXmlTreeStringValue("PayeeInfo().getAcctNo"));
        //代付客户信息有则上送 证件类型 (已确认可不上送)
        CustomerInfo customerInfo = new CustomerInfo();
        customerInfo.setCustName(xmlTreeUtil.getXmlTreeStringValue("PayeeInfo().getAcctName"));
        repayRequest.setCustomerInfo(customerInfo);
        //订单信息 金额及币种
        repayRequest.setOrderAmt(xmlTreeUtil.getXmlTreeStringValue("TxnAmt"));
        repayRequest.setOrderCcy(xmlTreeUtil.getXmlTreeStringValue("TxnCrcyCode"));
        //使用系统流水号
        repayRequest.setOrderId(sysSeqNum);
        repayRequest.setOrderTime(xmlTreeUtil.getXmlTreeStringValue("Header().getTransDate") + xmlTreeUtil.getXmlTreeStringValue("Header().getTransTime"));
        //根据业务类型转换得到资金来源，未配置的转换则默认填写00一般性付款
        repayRequest.setSourcesOfFunds(DEFAULT_SOURCE_OF_FUNDS);

        rglog.debug("UPAC 银联全渠道单笔代付请求:<{}>", JSON.toJSONString(repayRequest));
        return repayRequest;
    }

    @Override
    public PayOrderInfo generatePayOrderInfo(ChannelCallCfg channelCallCfg, OrderInfo orderInfo, Object request) throws Exception {
        XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
        PayOrderInfo payOrderInfo = new PayOrderInfo();
        RepayRequest repayRequest = (RepayRequest) request;
        BeanUtil.beanCopy(orderInfo.getUserOrderInfo(), payOrderInfo);
        if (orderInfo.getMchntOrderInfoList().size() == 1) {
            payOrderInfo.setMchntNo(orderInfo.getMchntOrderInfoList().get(0).getMchntNo());
        } else {
            payOrderInfo.setMchntNo(orderInfo.getUserOrderInfo().getGroupMchntNo());
        }
        payOrderInfo.setTxnNum(channelCallCfg.getTxnNum());
        payOrderInfo.setBizType(channelCallCfg.getBizType());
        payOrderInfo.setSysSeqNum(orderInfo.getUserOrderInfo().getSysSeqNum());
        payOrderInfo.setOrderCcy(orderInfo.getUserOrderInfo().getOrderCcy());
        payOrderInfo.setMsgDstId(channelCallCfg.getCallChannelId());
        payOrderInfo.setDstCallIndex(channelCallCfg.getCallIndex());
        payOrderInfo.setChannelSeqNum(Objects.requireNonNull(repayRequest).getHeader().getTraceNo());
        payOrderInfo.setChannelReconKey(repayRequest.getHeader().getTraceNo());
        payOrderInfo.setDstTxnNum(channelCallCfg.getCallChannelTxn());
        payOrderInfo.setPayType(PayTypeEnum.OTHER_BANK_CARD.getPayType());
        payOrderInfo.setPayerAcctType(AcctTypeEnum.ALL.getAcctType());
        payOrderInfo.setBizStatus(BizStatusEnum.PROCESSING.getStatus());
        payOrderInfo.setTransStatus(TransStatusEnum.TRANS_INIT.getStatus());
        payOrderInfo.setCreateTime(DateUtil.getCurrentDateTime("yyyy-MM-dd HH:mm:ss.SSS"));
        payOrderInfo.setUserId(orderInfo.getUserOrderInfo().getUserId());
        return payOrderInfo;
    }

    @Override
    public Object callProc(ChannelCallCfg channelCallCfg, Object request) throws Exception {
        RepayRequest repayRequest = (RepayRequest) request;
        /* Step1：调用接口，获取结果 */
        Result<RepayResponse> callResult;
        DubboService dubboService = new DubboServiceImpl();
        if (AppParamConstant.YES.equals(channelCallCfg.getSyncCallFlag())) {
            /* Step1.1：异步调用 */
            int iReturnCode;
            int callTimes = 0 == channelCallCfg.getSyncQueryRepeatNum() ? 1 : channelCallCfg.getSyncQueryRepeatNum();
            int gatTime = channelCallCfg.getSyncQueryRepeatTime();
            int gatType = StringUtil.isEmptyOrNull(channelCallCfg.getSyncQueryGapType()) ? 0 : Integer.parseInt(channelCallCfg.getSyncQueryGapType());
            if (ChannelCallModeEnum.LOCAL.getMode().equals(channelCallCfg.getChannelCallMode())) {
                /* Step1.1.1：异步应用内调用 */
                Class clasz = Class.forName(ShareServiceConstant.UPAC_CREDIT_SERVICE_INNER_PATH);
                iReturnCode = dubboService.asynCallDubboInnerMethod(clasz, ShareServiceConstant.UPAC_SINGLE_REPAY_METHOD, repayRequest, channelCallCfg.getSyncResultServiceName(), callTimes, gatType, gatTime);
            } else if (ChannelCallModeEnum.REMOTE.getMode().equals(channelCallCfg.getChannelCallMode())) {
                /* Step1.1.2：异步远程调用 */
                iReturnCode = dubboService.asynCallDubboService(ShareServiceConstant.UPAC_CREDIT_SERVICE, ShareServiceConstant.UPAC_SINGLE_REPAY_METHOD, repayRequest, channelCallCfg.getSyncResultServiceName(), callTimes, gatType, gatTime);
            } else {
                rglog.error("不支持的通道服务调用方式:{}，交易拒绝!", channelCallCfg.getChannelCallMode());
                throw new BizException(OltpRpcdEnum.CALL_BIZ_SERVICE_ERROR);
            }
            if (0 == iReturnCode) {
                return new BizResponse<>(OltpRpcdEnum.TRANS_SUCCESS.getRespCode(), OltpRpcdEnum.TRANS_SUCCESS.getRespDesc());
            } else {
                return new BizResponse<>(OltpRpcdEnum.CALL_BIZ_SERVICE_ERROR.getRespCode(), OltpRpcdEnum.CALL_BIZ_SERVICE_ERROR.getRespDesc());
            }
        } else {
            /* Step1.2：同步调用 */
            if (ChannelCallModeEnum.LOCAL.getMode().equals(channelCallCfg.getChannelCallMode())) {
                /* Step1.2.1：同步应用内调用 */
                Class clasz = Class.forName(ShareServiceConstant.UPAC_CREDIT_SERVICE_INNER_PATH);
                callResult = (Result<RepayResponse>) dubboService.callDubboInnerMethod(clasz, ShareServiceConstant.UPAC_SINGLE_REPAY_METHOD, repayRequest);
            } else if (ChannelCallModeEnum.REMOTE.getMode().equals(channelCallCfg.getChannelCallMode())) {
                /* Step1.2.2：同步远程调用 */
                callResult = (Result<RepayResponse>) dubboService.callDubboService(ShareServiceConstant.UPAC_CREDIT_SERVICE, ShareServiceConstant.UPAC_SINGLE_REPAY_METHOD, repayRequest);
            } else {
                rglog.error("不支持的通道服务调用方式:{}，交易拒绝!", channelCallCfg.getChannelCallMode());
                throw new BizException(OltpRpcdEnum.CALL_BIZ_SERVICE_ERROR);
            }
        }
        return callResult;
    }

    @Override
    public Object querySyncCallResult(PayOrderInfo payOrderInfo, Object request) {
        return null;
    }

    @Override
    public OrderInfo callResultOrderProc(OrderInfo orderInfo, String payOrderIndex, TransStatusEnum transStatusEnum, Object response) {
        OrderInfo updateOrderInfo = new OrderInfo();
        Result<RepayResponse> callResult = (Result<RepayResponse>) response;
        Optional<PayOrderInfo> payOrderInfoOpt = orderInfo.getPayOrderInfoList().stream().filter(item -> item.getDstCallIndex().equals(payOrderIndex)).findFirst();
        if (payOrderInfoOpt.isPresent() && null != callResult && null != callResult.getResult()) {
            RepayResponse repayResponse = callResult.getResult();
            PayOrderInfo payOrderInfo = payOrderInfoOpt.get();
            payOrderInfo.setTransStatus(transStatusEnum.getStatus());
            payOrderInfo.setRespCode(repayResponse.getRespCode());
            payOrderInfo.setRespDesc(repayResponse.getRespDesc());
            payOrderInfo.setUpdateTime(DateUtil.getCurrentDateTime("yyyy-MM-dd HH:mm:ss.SSS"));
            switch (transStatusEnum) {
                case TRANS_SUCC:
                    payOrderInfo.setBizStatus(BizStatusEnum.FINISH.getStatus());
                    /* 用户订单信息处理 */
                    updateOrderInfo.setUserOrderInfo(orderInfo.getUserOrderInfo());
                    /* 商户订单信息处理 */
                    payOrderInfo.setSettleDate(DateUtil.getCurrentDate());

                    break;
                case TRANS_TIMEOUT:
                    payOrderInfo.setBizStatus(BizStatusEnum.PROCESSING.getStatus());
                    break;
                case SYSTEM_REJECT:
                    payOrderInfo.setBizStatus(BizStatusEnum.FAILED.getStatus());
                    break;
                default:
                    break;
            }
            List<PayOrderInfo> payOrderInfoList = new ArrayList<>();
            payOrderInfoList.add(payOrderInfo);
            updateOrderInfo.setPayOrderInfoList(payOrderInfoList);
        }
        return updateOrderInfo;
    }
}
